﻿Shader "Custom/WaterHigh"
{
	Properties
	{
		_ReflectionTex("Internal reflection", 2D) = "white" {}

		_MainTex("Fallback texture", 2D) = "black" {}
		_BumpMap("Normals ", 2D) = "bump" {}

		_DistortParams("Distortions (Bump waves, Reflection, Fresnel power, Fresnel bias)", Vector) = (0.5 ,0.2, 5, 0.02)
		_InvFadeParemeter("Auto blend parameter (Edge, Shore, Distance scale)", Vector) = (2 ,0.0, 0.0, 0.0)

		_AnimationTiling("Animation Tiling (Displacement)", Vector) = (0.4 ,0.391, 0.56, 0.7)
		_AnimationDirection("Animation Direction (displacement)", Vector) = (2.0 ,1.0, -1.0, 1.0)

		_BumpTiling("Bump Tiling", Vector) = (0.02 ,0.02, 0.02, 0.02)
		_BumpDirection("Bump Direction & Speed", Vector) = (1.0 ,30,20, -20)

		_FresnelScale("FresnelScale", Range(0.0, 4.0)) = 0.15

		_BaseColor("Base color", COLOR) = (0.08235, 0.29411, 0.4838, 0.8)
		_ReflectionColor("Reflection color", COLOR) = (0.8784, 0.9607, 1.0, 0.8)
		_SpecularColor("Specular color", COLOR) = (1, 1, 1, 1)

		_WorldLightDir("Specular light direction", Vector) = (0.02, -0.1735908, 0.9847186, 0.0)
		_Shininess("Shininess", Range(2.0, 65535.0)) = 65535

		_GerstnerIntensity("Per vertex displacement", Float) = 1.0
		_GerstnerScale("Per vertex displacement scale", Float) = 1.0
		_GAmplitude("Wave Amplitude", Vector) = (0.3 ,0.35, 0.25, 0.25)
		_GFrequency("Wave Frequency", Vector) = (1.3, 1.35, 1.25, 1.25)
		_GSteepness("Wave Steepness", Vector) = (1.0, 1.0, 1.0, 1.0)
		_GSpeed("Wave Speed", Vector) = (1.2, 1.375, 1.1, 1.5)
		_GDirectionAB("Wave Direction", Vector) = (0.3 ,0.85, 0.85, 0.25)
		_GDirectionCD("Wave Direction", Vector) = (0.1 ,0.9, 0.5, 0.5)
	}
		CGINCLUDE
		#include "UnityCG.cginc"
		#include "WaterInclude.cginc"

		struct appdata
		{
			float4 vertex : POSITION;
			float3 normal : NORMAL;
		};

		struct v2f_low
		{
			float4 pos : SV_POSITION;
			float3 viewInterpolator : TEXCOORD0;
			float4 bumpCoords : TEXCOORD1;
			UNITY_FOG_COORDS(2)
		};

		struct v2f_medium
		{
			float4 pos : SV_POSITION;
			float4 normalInterpolator : TEXCOORD0;
			float3 viewInterpolator : TEXCOORD1;
			float4 bumpCoords : TEXCOORD2;
			float4 screenPos : TEXCOORD3;
			UNITY_FOG_COORDS(4)
		};

		struct v2f
		{
			float4 pos : SV_POSITION;
			float4 normalInterpolator : TEXCOORD0;
			float3 viewInterpolator : TEXCOORD1;
			float4 bumpCoords : TEXCOORD2;
			float4 screenPos : TEXCOORD3;
			float4 grabPassPos : TEXCOORD4;
			UNITY_FOG_COORDS(5)
		};

		sampler2D _BumpMap;
		sampler2D _ReflectionTex;
		sampler2D _RefractionTex;
		sampler2D _ShoreTex;
		sampler2D_float _CameraDepthTexture;

		uniform float4 _RefrColorDepth;
		uniform float4 _SpecularColor;
		uniform float4 _BaseColor;
		uniform float4 _ReflectionColor;

		uniform float4 _InvFadeParemeter;

		uniform float _Shininess;
		uniform float _GerstnerScale;
		uniform float4 _WorldLightDir;

		uniform float4 _DistortParams;
		uniform float _FresnelScale;
		uniform float4 _BumpTiling;
		uniform float4 _BumpDirection;

		uniform float4 _GAmplitude;
		uniform float4 _GFrequency;
		uniform float4 _GSteepness;
		uniform float4 _GSpeed;
		uniform float4 _GDirectionAB;
		uniform float4 _GDirectionCD;

		#define PER_PIXEL_DISPLACE _DistortParams.x
		#define REALTIME_DISTORTION _DistortParams.y
		#define FRESNEL_POWER _DistortParams.z
		#define VERTEX_WORLD_NORMAL i.normalInterpolator.xyz
		#define DISTANCE_SCALE _InvFadeParemeter.z
		#define FRESNEL_BIAS _DistortParams.w

		v2f_low vert200(appdata_full v)
		{
			v2f_low o;

			half3 worldSpaceVertex = mul(unity_ObjectToWorld, v.vertex).xyz;
			half2 tileableUv = worldSpaceVertex.xz;

			o.bumpCoords.xyzw = (tileableUv.xyxy + _Time.xxxx * _BumpDirection.xyzw) * _BumpTiling.xyzw;

			o.viewInterpolator.xyz = worldSpaceVertex - _WorldSpaceCameraPos;

			o.pos = UnityObjectToClipPos(v.vertex);

			UNITY_TRANSFER_FOG(o, o.pos);
			return o;
		}

		half4 frag200(v2f_low i) : SV_Target
		{
			half3 N = PerPixelNormal(_BumpMap, i.bumpCoords, half3(0,1,0), PER_PIXEL_DISPLACE);
			half3 V = normalize(i.viewInterpolator.xyz);
			half3 L = _WorldLightDir.xyz;
			half3 H = normalize(V + L);

			float nh = max(0, dot(N, -H));
			float alpha = _Shininess;

			float spec = (alpha * 0.125 + 0.25) * max(0.0, pow(nh, alpha));
			spec *= lerp(0.02, 1.0, pow(1 - dot(L, H), 5)) / 3.1415926h;

			N.xz *= _FresnelScale;
			half fresnel = Fresnel(V, N, FRESNEL_BIAS, FRESNEL_POWER);

			half4 baseColor = _BaseColor;
			baseColor = lerp(baseColor, _ReflectionColor, fresnel);
			baseColor.rgb += spec * _SpecularColor.rgb;
			baseColor.a = saturate(2.0 * fresnel + 0.5);

			UNITY_APPLY_FOG(i.fogCoord, baseColor);
			return baseColor;
		}

		v2f_medium vert300(appdata_full v)
		{
			v2f_medium o;

			half3 worldSpaceVertex = mul(unity_ObjectToWorld, (v.vertex)).xyz;
			half3 vtxForAni = (worldSpaceVertex).xzz;

			half3 nrml;
			half3 offsets;
			Gerstner(
				offsets, nrml, v.vertex.xyz, vtxForAni,						// offsets, nrml will be written
				_GAmplitude,												// amplitude
				_GFrequency,												// frequency
				_GSteepness,												// steepness
				_GSpeed,													// speed
				_GDirectionAB,												// direction # 1, 2
				_GDirectionCD												// direction # 3, 4
			);

			v.vertex.xyz += offsets * _GerstnerScale;

			half2 tileableUv = worldSpaceVertex.xz;

			o.bumpCoords.xyzw = (tileableUv.xyxy + _Time.xxxx * _BumpDirection.xyzw) * _BumpTiling.xyzw;

			o.viewInterpolator.xyz = worldSpaceVertex - _WorldSpaceCameraPos;

			o.pos = UnityObjectToClipPos(v.vertex);

			o.screenPos = ComputeNonStereoScreenPos(o.pos);

			o.normalInterpolator.xyz = nrml;

			o.normalInterpolator.w = 1;//GetDistanceFadeout(o.screenPos.w, DISTANCE_SCALE);

			UNITY_TRANSFER_FOG(o, o.pos);
			return o;
		}

		half4 frag300(v2f_medium i) : SV_Target
		{
			half3 worldNormal = PerPixelNormal(_BumpMap, i.bumpCoords, VERTEX_WORLD_NORMAL, PER_PIXEL_DISPLACE);
			half3 viewVector = normalize(i.viewInterpolator.xyz);

			half4 distortOffset = half4(worldNormal.xz * REALTIME_DISTORTION * 10.0, 0, 0);
			half4 screenWithOffset = i.screenPos + distortOffset;

	#ifdef WATER_REFLECTIVE
			half4 rtReflections = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(screenWithOffset));
	#endif

			half3 N = worldNormal;
			half3 L = _WorldLightDir.xyz;
			half3 H = normalize(viewVector.xyz + L);

			float nh = max(0, dot(N, -H));
			float alpha = _Shininess;

			float spec = (alpha * 0.125 + 0.25) * max(0.0, pow(nh, alpha));
			spec *= lerp(0.02, 1.0, pow(1 - dot(L, H), 5)) / 3.1415926h;

			half4 edgeBlendFactors = half4(1.0, 0.0, 0.0, 0.0);

	#ifdef WATER_EDGEBLEND_ON
			half depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos));
			depth = LinearEyeDepth(depth);
			edgeBlendFactors = saturate(_InvFadeParemeter * (depth - i.screenPos.z));
	#endif

			worldNormal.xz *= _FresnelScale;
			half fresnel = Fresnel(viewVector, worldNormal, FRESNEL_BIAS, FRESNEL_POWER);

			half4 baseColor = _BaseColor;
	#ifdef WATER_REFLECTIVE
			baseColor = lerp(baseColor, lerp(rtReflections,_ReflectionColor,_ReflectionColor.a), saturate(fresnel * 1.0));
	#else
			baseColor = _ReflectionColor;//lerp (baseColor, _ReflectionColor, saturate(fresnel * 2.0));
	#endif

			baseColor = baseColor + spec * _SpecularColor;

			baseColor.a = edgeBlendFactors.x * saturate(0.5 + fresnel * 1.0);
			UNITY_APPLY_FOG(i.fogCoord, baseColor);
			return baseColor;
		}

		v2f vert(appdata_full v)
		{
			v2f o;

			half3 worldSpaceVertex = mul(unity_ObjectToWorld, (v.vertex)).xyz;
			half3 vtxForAni = (worldSpaceVertex).xzz;

			half3 nrml;
			half3 offsets;

			Gerstner(
				offsets, nrml, v.vertex.xyz, vtxForAni,						// offsets, nrml will be written
				_GAmplitude,												// amplitude
				_GFrequency,												// frequency
				_GSteepness,												// steepness
				_GSpeed,													// speed
				_GDirectionAB,												// direction # 1, 2
				_GDirectionCD												// direction # 3, 4
			);

			v.vertex.xyz += offsets * _GerstnerScale;

			half2 tileableUv = worldSpaceVertex.xz;

			o.bumpCoords.xyzw = (tileableUv.xyxy + _Time.xxxx * _BumpDirection.xyzw) * _BumpTiling.xyzw;
			o.viewInterpolator.xyz = worldSpaceVertex - _WorldSpaceCameraPos;
			o.pos = UnityObjectToClipPos(v.vertex);

			ComputeScreenAndGrabPassPos(o.pos, o.screenPos, o.grabPassPos);

			o.normalInterpolator.xyz = nrml;
			o.normalInterpolator.w = 1;//GetDistanceFadeout(o.screenPos.w, DISTANCE_SCALE);

			UNITY_TRANSFER_FOG(o, o.pos);
			return o;
		}

		half4 frag(v2f i) : SV_Target
		{
			half3 N = PerPixelNormal(_BumpMap, i.bumpCoords, VERTEX_WORLD_NORMAL, PER_PIXEL_DISPLACE);
			half3 V = normalize(i.viewInterpolator.xyz);

			half3 L = _WorldLightDir.xyz;
			half3 H = normalize(V + L);

			half4 distortOffset = half4(N.xz * REALTIME_DISTORTION * 10.0, 0, 0);			
			half4 grabWithOffset = i.grabPassPos + distortOffset;

			half4 rtRefractionsNoDistort = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(i.grabPassPos));
			half4 rtRefractions = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(grabWithOffset));

	#ifdef WATER_REFLECTIVE
			half4 screenWithOffset = i.screenPos + distortOffset;
			half4 rtReflections = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(screenWithOffset));
	#endif

	#ifdef WATER_REFLECTIVE
			half4 reflectionColor = lerp(rtReflections,_ReflectionColor,_ReflectionColor.a);
	#else
			half4 reflectionColor = _ReflectionColor;
	#endif

			float nh = max(0, dot(N, -H));
			float alpha = _Shininess;

			float3 spec = (alpha * 0.125 + 0.25) * max(0.0, pow(nh, alpha));
			spec *= lerp(0.02, _SpecularColor, pow(1 - saturate(dot(L, H)), 5)) / 3.1415926;
			spec *= _SpecularColor;

			N.xz *= _FresnelScale;

			half fresnel = Fresnel(V, N, FRESNEL_BIAS, FRESNEL_POWER);

			half4 baseColor = _BaseColor;
			baseColor = lerp(lerp(rtRefractions, baseColor, baseColor.a), reflectionColor, fresnel);
			baseColor.rgb += spec;

	#ifdef WATER_EDGEBLEND_ON
			half refrFix = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(grabWithOffset));

			if (LinearEyeDepth(refrFix) < i.screenPos.z)
				rtRefractions = rtRefractionsNoDistort;

			half depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos));
			depth = LinearEyeDepth(depth);

			baseColor.a = saturate(_InvFadeParemeter.x * (depth - i.screenPos.w));
	#else
			baseColor.a = 1;
	#endif
			

			UNITY_APPLY_FOG(i.fogCoord, baseColor);

			return baseColor;
		}

		ENDCG

		Subshader
		{
			Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }

				Lod 500
				ColorMask RGB

				GrabPass{ "_RefractionTex" }

				Pass
			{
				Blend SrcAlpha OneMinusSrcAlpha
				ZTest LEqual
				ZWrite Off
				Cull Off

				CGPROGRAM

				#pragma target 3.0

				#pragma vertex vert
				#pragma fragment frag
				#pragma multi_compile_fog

				#pragma multi_compile WATER_VERTEX_DISPLACEMENT_ON WATER_VERTEX_DISPLACEMENT_OFF
				#pragma multi_compile WATER_EDGEBLEND_ON WATER_EDGEBLEND_OFF
				#pragma multi_compile WATER_REFLECTIVE WATER_SIMPLE

				ENDCG
			}
		}

		Subshader
		{
			Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }

				Lod 300
				ColorMask RGB

				Pass
			{
				Blend SrcAlpha OneMinusSrcAlpha
				ZTest LEqual
				ZWrite Off
				Cull Off

				CGPROGRAM

				#pragma target 3.0

				#pragma vertex vert300
				#pragma fragment frag300
				#pragma multi_compile_fog

				#pragma multi_compile WATER_VERTEX_DISPLACEMENT_ON WATER_VERTEX_DISPLACEMENT_OFF
				#pragma multi_compile WATER_EDGEBLEND_ON WATER_EDGEBLEND_OFF
				#pragma multi_compile WATER_REFLECTIVE WATER_SIMPLE

				ENDCG
			}
		}

		Subshader
		{
			Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }

			Lod 300
			ColorMask RGB

			Pass
			{
				Blend SrcAlpha OneMinusSrcAlpha
				ZTest LEqual
				ZWrite Off
				Cull Off

				CGPROGRAM

				#pragma vertex vert200
				#pragma fragment frag200
				#pragma multi_compile_fog

				ENDCG
			}
		}

		Fallback "Transparent/Diffuse"
}